package org.summer.gateway.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.summer.common.http.Result;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * 服务响应前端信息处理器
 */
@Log4j2
@Component
@RequiredArgsConstructor
public class ServerResponseHandler {
    private final ObjectMapper objectMapper;

    /**
     * 处理响应给前端数据
     * @param exchange 服务请求上下文
     * @param result 需要反回给前端的数据
     * @param httpStatus http状态码
     * @param <T> 数据类型
     */
    public <T> Mono<Void> handlerResponse(ServerWebExchange exchange, Result<T> result,HttpStatus httpStatus) {
        log.debug("处理响应数据信息: {},{}",httpStatus,result);
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(httpStatus);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return Mono.defer(() -> response.writeWith(Mono.just(response.bufferFactory().wrap(dataToByteArray(result)))));
    }

    /**
     * 处理响应给前端数据
     */
    public <T> Mono<Void> handlerResponse(ServerWebExchange exchange, Result<T> result){
        log.debug("处理响应数据信息: {}",result);
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return Mono.defer(() -> response.writeWith(Mono.just(response.bufferFactory().wrap(dataToByteArray(result)))));
    }

    /**
     * 将响应数据转换为字节数组
     */
    private <T> byte[] dataToByteArray(Result<T> data){
        try {
           return this.objectMapper.writeValueAsString(data).getBytes(StandardCharsets.UTF_8);
        } catch (JsonProcessingException e) {
            log.error("序列化数响应数据据失败",e);
            throw new RuntimeException("序列化数响应数据据失败",e);
        }
    }
}
